package com.mmd.base.auth;

import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.mmd.base.exception.ApplicationException;
import com.mmd.base.pojo.entity.UserInfo;
import com.mmd.core.constant.KeyConstant;
import com.mmd.core.enums.LoginEnum;
import com.mmd.core.enums.ResultEnum;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;

public class UserContextHolder {

    /**
     * 设置上下文信息
     * @param userInfo 用户信息
     * @param token jwt信息
     * @param <T> 其他信息类型
     */
    public static <T> void setSecurityContextHolder(UserInfo<T> userInfo,String token)
    {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userInfo,userInfo.getAuthentication());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        RpcContext.getClientAttachment().setAttachment(KeyConstant.DUBBO_AUTHENTICATION, token);
    }

    /**
     * 从Security中获取上下文
     */
    public static UserInfo<Object> getSecurityContextHolder()
    {
        return getSecurityContextHolder(Object.class);
    }

    /**
     * 从Security中获取上下文
     */
    public static <T> UserInfo<T> getSecurityContextHolder(Class<T> tClass) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(authentication == null){
            // 从dubbo上下文获取token
            String token = RpcContext.getServiceContext().getAttachment(KeyConstant.DUBBO_AUTHENTICATION);
            if(!StringUtils.isEmpty(token)){
                // 获取jwt信息
                return TokenTemplate.getSubject(token, tClass);
            }
        }
        Assert.notNull(authentication,ResultEnum.LOGIN.getMessage());
        Object principal = authentication.getPrincipal();
        Assert.notNull(principal,ResultEnum.LOGIN.getMessage());
        UserInfo<T> userInfo = null;
        try{
            userInfo = (UserInfo) principal;
            String jsonString = JSONObject.toJSONString(userInfo.getOther());
            T t = JSONObject.parseObject(jsonString).toJavaObject(tClass);
            userInfo.setOther(t);
        }catch (Exception e){
            Assert.notNull(userInfo,ResultEnum.LOGIN.getMessage());
        }
        return userInfo;
    }

    /**
     * 退出登录销毁会话信息
     */
    public static void logout()
    {
        UserInfo<Object> securityContextHolder = getSecurityContextHolder();
        logout(securityContextHolder.getAuthentication());
    }

    /**
     * 退出登录销毁会话信息
     */
    public static void logout(String key)
    {
        StringRedisTemplate redisTemplate = SpringUtil.getBean(StringRedisTemplate.class);
        redisTemplate.delete(key);
        SecurityContextHolder.clearContext();
    }

    /**
     * 获取请求来源
     */
    public static LoginEnum loginEnum(HttpServletRequest request) throws ApplicationException {
        String requestHeader = request.getHeader(KeyConstant.REQUEST_SOURCE);
        try{
            return LoginEnum.valueOf(requestHeader);
        }catch (Exception ignored){
            throw new ApplicationException(ResultEnum.FAIL_REQUEST_SOURCE);
        }
    }
}
